/*
**NCS provide dev fsm for controlling the dev state
**
**This module provide the interface of dev(pp,sig,rx,rcst) fsm
**The state of dev change to other state by the current state
**and event of receiving.
**
**Copyright (C) 2016-1 andisat <www.andisat.com>
**
**Author: andisat
**Date:2016-1
**
*/

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "event.h"
#include "ncs_list.h"
#include "ncs_log.h"
#include "ncs_network.h"
#include "ncs_sig.h"
#include "ncs_msg.h"
#include "ncs_serv.h"
#include "ncs_fsm.h"
#include "ncs_resmng.h"


int ncs_allocres_by_rcst(struct _STR_CHANNEL_ID_ *ptxcha,
    struct _STR_CHANNEL_ID_ *prxcha)
{
    if(!ptxcha || !prxcha)
        return -1;

    if(ncs_resAlloc_byRcst((devIdIfo *)ptxcha,(devIdIfo *)prxcha))
        return 0;
    else
        return -1;
}

int ncs_allocres_bod_by_rcst(struct _STR_CHANNEL_ID_ *ptxcha,
    struct _STR_CHANNEL_ID_ *pnewrxcha,struct _STR_CHANNEL_ID_ *poldrxcha)
{
    rxInfoForBodQuery resinfo_bod;
    
    if(!ptxcha)
        return FALSE;
        
    if(ncs_resBodAlloc_byRcst((devIdIfo *)ptxcha,&resinfo_bod))
    {
        if(pnewrxcha)
        {
            pnewrxcha->devId=resinfo_bod.newRxDevIDInfo.devID;
            pnewrxcha->chaId=resinfo_bod.newRxDevIDInfo.chanId;
        }

        if(poldrxcha)
        {
            poldrxcha->devId=resinfo_bod.preRxDevIDInfo.devID;
            poldrxcha->chaId=resinfo_bod.preRxDevIDInfo.chanId;
        }

        return TRUE;
    }
    
    return FALSE;
}

int ncs_bodrel_by_rcst(struct _STR_CHANNEL_ID_ *ptxcha)
{
    if(!ptxcha)
        return FALSE;

    return ncs_release_bodRes((devIdIfo *)ptxcha);
}

int ncs_reallocres_by_rcst(struct _STR_CHANNEL_ID_ *ptxcha,
    struct _STR_CHANNEL_ID_ *pnewrxcha,struct _STR_CHANNEL_ID_ *poldrxcha)
{
    devIdIfo rxInfo;
        
    if(!ptxcha)
        return FALSE;
    
    if(ncs_reGet_availPhyChan((devIdIfo *)ptxcha,&rxInfo))
    {
        if(pnewrxcha)
        {
            pnewrxcha->devId=rxInfo.devID;
            pnewrxcha->chaId=rxInfo.chanId;
        }

        if(poldrxcha)
        {
            poldrxcha->devId=rxInfo.devID;
            poldrxcha->chaId=rxInfo.chanId;
        }

        return TRUE;
    }
    else
        return FALSE;
}

int ncs_getrcst_by_rx(struct _STR_CHANNEL_ID_ *prxcha,
    struct _STR_CHANNEL_ID_ *ptxcha)
{
    if(!ptxcha || !prxcha)
        return FALSE;

    return ncs_get_rcstInfoByRx(prxcha,ptxcha);
}

int ncs_getres_by_rcst(struct _STR_CHANNEL_ID_ *ptxcha,
    struct _STR_CHANNEL_ID_ *prxcha,struct _STR_RESOURCE_ *presource)
{
    rcstResInfo resInfo;
    
    if(!ptxcha)
        return -1;
    
    if(ncs_get_resInfoByRcst(ptxcha,&resInfo))
    {
        if(prxcha)
        {
            prxcha->devId=resInfo.RxMD_ID;
            prxcha->chaId=resInfo.RxCH_ID;
        }
        
        if(presource)
        {
            presource->freq=resInfo.CentFreq;
            presource->BW=resInfo.BW;
        }
        
        return 0;
    }
    else
        return -1;
}

int ncs_relres_by_rcst(struct _STR_CHANNEL_ID_ *pchaId)
{
    if(!pchaId)
        return -1;

    if(FALSE==ncs_release_allRes((devIdIfo *)pchaId))
        ncs_log(ERR,"%s release resource failure",__func__);

    return 0;
}


int poll_rcst_offline(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    struct dev_obj *rx;
    struct _STR_CHANNEL_ID_ rxchaId;
    struct _STR_CHANNEL_ID_ txchaId;
    
    if(!ncs || !dev)
        return -1;

    txchaId.devId=dev->devId;
    txchaId.chaId=PATH_FIRST;

    if(ncs_getres_by_rcst(&txchaId, &rxchaId, NULL))
    {
        if(rx=ncs_find_rx(ncs,rxchaId.devId))
            ncs2rx_closerxpath_req(ncs, rx, &rxchaId);
    }

    ncs_relres_by_rcst(&txchaId);

    return 0;
}

int rcst_bod_rcst2ncs_req(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    struct tlv_hdr *ptlv;
    struct dev_obj *newrx,*oldrx;
    struct _STR_CHANNEL_ID_ *ptxchaId;
    struct _STR_CHANNEL_ID_ newrxchaId;
    struct _STR_CHANNEL_ID_ oldrxchaId;
    
    if(!ncs || !dev || !arg)
        return -1;
    
    ptlv=(struct tlv_hdr *)arg;
    if(len != (ntohl(ptlv->len)+TLV_HEAD_LEN))
        return -1;
    
    ptxchaId=(struct _STR_CHANNEL_ID_ *)(ptlv+1);
    if(dev->devId != ntohl(ptxchaId->devId))
        return -1;

    if(ncs_allocres_bod_by_rcst(ptxchaId,&newrxchaId,&oldrxchaId))
    {
        if(oldrx=ncs_find_rx(ncs,oldrxchaId.devId))
            ncs2rx_closerxpath_req(ncs,oldrx,&oldrxchaId);
        
        if(newrx=ncs_find_rx(ncs,newrxchaId.devId))
        {
            ncs2rx_openrxpath_req(ncs,newrx,&newrxchaId);
            SET_BIT(dev->flag,DEV_FLAG_BOD);
        }

        return 0;
    }
    else
        return -1;  
}

int rcst_bodrel_rcst2ncs_req(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    struct dev_obj *rx;
    struct _STR_CHANNEL_ID_ txchaId;
    struct _STR_CHANNEL_ID_ rxchaId;
    
    if(!ncs || !dev || !arg)
        return -1;
    
    txchaId.devId=dev->devId;
    txchaId.chaId=PATH_FIRST;
    
    if(ncs_bodrel_by_rcst(&txchaId))
    {
        if(ncs_getres_by_rcst(&txchaId,&rxchaId,NULL))
            if(rx=ncs_find_rx(ncs,rxchaId.devId)){
                ncs2rx_openrxpath_req(ncs, rx, &rxchaId);
                SET_BIT(dev->flag,DEV_FLAG_BODREL);
            }
    }

    return 0;
}

int rcst_allocres_success(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    struct dev_obj *rx;
    struct _STR_CHANNEL_ID_ rxchaId;
    struct _STR_CHANNEL_ID_ txchaId;
    struct _STR_RESOURCE_ resource;
    
    if(!ncs || !dev || !arg)
        return -1;
    
    rx=(struct dev_obj *)arg;      
    rxchaId.devId=rx->devId;
    rxchaId.chaId=(char)len;
    
    ncs2rx_openrxpath_req(ncs, rx, &rxchaId);
    
    return 0;
}

int rcst_allocres_failure(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{    
    if(!ncs || !dev)
        return -1;
    
    ncs2rcst_resalloc_ack(ncs,dev,FAILURE);
    
    if(dev->state==RCST_ONLINE_OPENRX)
    {
        struct _STR_CHANNEL_ID_ txchaId;
        txchaId.devId=dev->devId;
        txchaId.chaId=PATH_FIRST;
        ncs_relres_by_rcst(&txchaId);
    }
    
    return 0;
}

int rcst_openrx_success(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    int ret;
    
    if(!ncs || !dev)
        return -1;

    ret=ncs2rcst_resalloc_ack(ncs,dev,SUCCESS);
    
    return ret;
}

int rcst_openrx_failure(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    return 0;
}

int rcst_logon_success(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    struct dev_set *rcstset;
    struct timeval timeout;

    if(!ncs || !dev)
        return -1;

    rcstset=ncs->sig_set;
    rcstset->count += 1;
        
    /*start poll timer event*/
    if(!rcstset->poll_timerev)
        ncs_start_dev_poll_event(ncs,dev);
     
    /*send rcst's configure to rcst*/
    ncs2rcst_send_allcfg(ncs,dev);

    if(CHECK_BIT(dev->flag,DEV_FLAG_LOCK))
    {
        struct dev_obj *rx;
        struct _STR_CHANNEL_ID_ txchaId;
        struct _STR_CHANNEL_ID_ rxchaId;
        struct _STR_RESOURCE_ resource;
        
        txchaId.devId=dev->devId;
        txchaId.chaId=PATH_FIRST;
        if(ncs_getres_by_rcst(&txchaId, &rxchaId,&resource)
            && (rx=ncs_find_rx(ncs, rxchaId.devId)))
        {                      
            ncs2rcst_locktxpath_req(ncs,dev,&txchaId,&resource);
            ncs2rx_openrxpath_req(ncs,rx,&rxchaId);
        }
        else
            ncs_log(ERR,"%s get the lock information failure",__func__);
    }
    
    return 0;
}

int rcst_delrcst_nms2ncs(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    if(ncs && dev)
        ncs_del_modem(ncs,dev);
    
    return 0;
}

int rcst_procfault_rcst2ncs(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    struct dev_obj *rx;
    struct _STR_CHANNEL_ID_ rxchaId;
    struct _STR_CHANNEL_ID_ txchaId;

    if(!ncs || !dev)
        return -1;

    txchaId.devId=dev->devId;
    txchaId.chaId=PATH_FIRST;
    if(ncs_getres_by_rcst(&txchaId, &rxchaId, NULL))
    {
        if((dev->state==RCST_ONLINE_OPENRX)
            || (dev->state==RCST_ACTIVE))
            if(rx=ncs_find_rx(ncs,rxchaId.devId))
                ncs2rx_closerxpath_req(ncs, rx, &rxchaId);

        if(dev->state==RCST_ACTIVE)
            ncs2rcst_relres_req(ncs, dev,&txchaId);
        
         ncs_relres_by_rcst(&txchaId);
    }
    
    return 0;
}

int rcst_allocres_rcst2ncs_req(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    int event;
    char result;
    FSM_CALLFUNC func;
    struct dev_obj *rx=NULL;
    struct _STR_CHANNEL_ID_ rxchaId;
    struct _STR_CHANNEL_ID_ *ptxchaId;
    
    if(!ncs || !dev || !arg || !len)
        return -1;

    ptxchaId=(struct _STR_CHANNEL_ID_ *)arg;
    if(dev->devId != ptxchaId->devId)
        return -1;
    
    if(0==ncs_allocres_by_rcst(ptxchaId,&rxchaId))
    {
        if(rx=ncs_find_rx(ncs,rxchaId.devId))
            event=RCST_RESALLOC_SUCCESS;
    }
    else
        event=RCST_RESALLOC_FAILURE;

    if(func=RCST_FSM[dev->state][event].func)
        if(-1 != func(ncs,dev,rx,rxchaId.chaId))
            rcst_fsm_change(dev,event);
        
    return 0;     
}

int rcst_closercst_rx2rcst_req(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    int ret;
    struct _STR_CHANNEL_ID_ *pchaId;

    if(!ncs || !dev || !arg)
        return -1;
   
    pchaId=(struct _STR_CHANNEL_ID_ *)arg;
    if(dev->devId != pchaId->devId)
        return -1;
    
    ret=ncs2rcst_relres_req(ncs, dev, pchaId);
    
    return ret;
}

int rcst_relres_rcst2ncs_req(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    struct tlv_hdr *ptlv;
    struct dev_obj *rx;
    struct _STR_CHANNEL_ID_ rxchaId;
    struct _STR_CHANNEL_ID_ *ptxchaId;
    
    if(!ncs || !dev || !arg || !len)
        return -1;

    ptlv=(struct tlv_hdr *)arg;    
    if((ptlv->type != _CHANNEL_ID_) 
        ||(ntohs(ptlv->len) != (len+TLV_HEAD_LEN)))
        return -1;

    ptxchaId=(struct _STR_CHANNEL_ID_ *)(ptlv+1);
    if(ptxchaId->devId != dev->devId)
        return -1;

    if(ncs_getres_by_rcst(ptxchaId,&rxchaId,NULL))
    {
        if((dev->state == RCST_ONLINE_OPENRX)
            || (dev->state == RCST_ACTIVE))
            ncs_relres_by_rcst(ptxchaId);
        
        if(dev->state != RCST_ONLINE_RELRES)
            ncs2rx_closerxpath_req(ncs,rx,&rxchaId);
    }
    
    ncs2rcst_relres_ack(ncs,dev,SUCCESS);

    return 0;
}

int rcst_relres_nms2ncs_req(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    int ret;
    struct dev_obj *rx;
    struct _STR_CHANNEL_ID_ *ptxcha;
    struct _STR_CHANNEL_ID_ rxcha;
    
    if(!ncs || !dev || !arg)
        return -1;
    
    ptxcha=(struct _STR_CHANNEL_ID_ *)arg;   
    if(ptxcha->devId != dev->devId)
        return -1;

    if(-1 != ncs_getres_by_rcst(ptxcha, &rxcha, NULL))
    {
        if(rx=ncs_find_rx(ncs, rxcha.devId))
            ncs2rx_closerxpath_req(ncs, rx, &rxcha);
    }
    else
        ncs_log(WARN,"%s the dev(Id:%d) hasn't resource",
            __func__,dev->devId);

    ret=ncs2rcst_relres_req(ncs,dev,ptxcha);

    return ret;
}

int rcst_relres_rcst2ncs_ack(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    struct tlv_hdr *ptlv;
    struct _STR_RESULT_ *presult;
    
    if(!ncs || !dev || !arg || !len)
        return -1;

    ptlv=(struct tlv_hdr *)arg;
    if(len != (ntohl(ptlv->len)+TLV_HEAD_LEN)
        || _RESULT_ != ptlv->type)
        return -1;

    presult=(struct _STR_RESULT_ *)(ptlv+1);
    if(SUCCESS != presult->result)
        ncs_log(ERR,"%s rcst release resource failure",__func__);

    struct _STR_CHANNEL_ID_ txcha;
    txcha.devId=dev->devId;
    txcha.chaId=PATH_FIRST;
    ncs_relres_by_rcst(&txcha);
    
    return 0;
}

int rcst_logoff_rcst2ncs_req(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    struct dev_obj *rx;
    struct _STR_CHANNEL_ID_ txchaId;
    struct _STR_CHANNEL_ID_ rxchaId;
    
    if(CHECK_BIT(dev->flag,DEV_FLAG_LOCK))
    {
        ncs_log(WARN,"%s the rcst(devId:%d) is locked",__func__,dev->devId);
        ncs2rcst_logoff_ack(ncs,dev,FAILURE);
        return -1;
    }

    txchaId.devId=dev->devId;
    txchaId.chaId=PATH_FIRST;
    if(ncs_getres_by_rcst(&txchaId, &rxchaId,NULL))
    {           
        if(rx=ncs_find_rx(ncs, rxchaId.devId))
            ncs2rx_closerxpath_req(ncs,rx,&rxchaId);

        ncs_relres_by_rcst(&txchaId);
    }

    ncs2rcst_logoff_ack(ncs,dev,SUCCESS);

    return 0;
}

int rcst_logoff_nms2ncs_req(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    struct dev_obj *rx;
    struct _STR_CHANNEL_ID_ txchaId;
    struct _STR_CHANNEL_ID_ rxchaId;
    
    if(!ncs || !dev)
        return -1;

    if(CHECK_BIT(dev->flag,DEV_FLAG_LOCK))
    {
        ncs_log(WARN,"%s the rcst(devId:%d) is locked",
            __func__,dev->devId);
        return -1;
    }

    txchaId.devId=dev->devId;
    txchaId.chaId=PATH_FIRST;
    if((dev->state != RCST_ONLINE_RELRES)
        && (dev->state != RCST_OFFLINE_RELRES))
    {  
        if(!ncs_getres_by_rcst(&txchaId,&rxchaId,NULL))
            if(rx=ncs_find_rx(ncs, rxchaId.devId))
                ncs2rx_closerxpath_req(ncs,rx,&rxchaId);
    }
    
    ncs2rcst_logoff_req(ncs,rx,&txchaId);
    
    return 0;
}

int rcst_logoff_rcst2ncs_ack(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    char result;
    struct tlv_hdr *ptlv;
    struct packet_ctl *packetctl;
    
    if(!ncs || !dev || !arg)
        return -1;

    if(len != (TLV_HEAD_LEN+sizeof(result))){
        ncs_log(ERR,"%s the packet is error",__func__);
        return -1;
    }

    ptlv=(struct tlv_hdr *)arg;
    result=*(char *)(ptlv+1);
    if(result==FAILURE)
        ncs_log(WARN,"%s rcst logoff failure",__func__);

    if((packetctl=find_packetctl(dev->out,dev->r_seq)))
    {
         if(event_del(packetctl->retry_timerev))
            ncs_log(ERR,"%s delete timer event failure",__func__);   
        del_packetctl(dev->out, packetctl);
    }

    struct _STR_CHANNEL_ID_ txchaId;
    txchaId.devId=dev->devId;
    txchaId.chaId=PATH_FIRST;
    ncs_relres_by_rcst(&txchaId);
    
    return 0;
}

int rcst_logon_rcst2ncs_req(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    char result;
    FSM_CALLFUNC func;
    
    if(!ncs || !dev || !arg || !len)
        return -1;

    if(dev->state == ONLINE && dev->try_flag)
        ncs2rcst_logon_ack(ncs,dev,SUCCESS);
    else if(dev->state == OFFLINE){
        result=logon_modem2ncs_req(ncs,dev,(struct tlv_hdr *)arg,len);
        ncs2rcst_logon_ack(ncs,dev,result);

        if(result == SUCCESS){
            if(func=RCST_FSM[dev->state][RCST_AUTH_SUCCESS].func)
                if(-1 != func(ncs,dev,NULL,0))
                    sig_fsm_change(dev, RCST_AUTH_SUCCESS); 
        }    
    }
        
    return -1;
}

int rcst_locktxpath_nms2ncs_req(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    struct carrierLock_msg *plock;
    struct _STR_CHANNEL_ID_ txchaId;
    struct _STR_CHANNEL_ID_ rxchaId;
    
    if(!ncs || !dev || !arg)
        return -1;

    SET_BIT(dev->flag,DEV_FLAG_LOCK);

    /*To do: set lock flag to database*/
    
    plock=(struct carrierLock_msg *)arg;
    txchaId.devId=plock->txdevId;
    txchaId.chaId=PATH_FIRST;
    rxchaId.devId=plock->rxdevId;
    rxchaId.chaId=plock->rxchaId;
    
    if((dev->state == RCST_ONLINE) || (dev->state == RCST_ACTIVE))
    {
        struct dev_obj *rx;
        ncs2rcst_locktxpath_req(ncs,dev,&txchaId,NULL);
        if(rx=ncs_find_rx(ncs,rxchaId.devId))
            ncs2rx_openrxpath_req(ncs,rx,&rxchaId);
    }

    return 0;
}

int rcst_locktxpath_rcst2ncs_ack(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    char result;
    struct tlv_hdr *ptlv;
    struct packet_ctl *packetctl;
    
    if(!ncs || !dev || !arg)
        return -1;

    if(len != (TLV_HEAD_LEN+sizeof(result)))
    {
        ncs_log(ERR,"%s the packet is error",__func__);
        return -1;
    }
    
    ptlv=(struct tlv_hdr *)arg;
    result=*(char *)(ptlv+1);
    if(result == FAILURE)
        ncs_log(ERR,"%s lock rcst failure",__func__);
        
    if(packetctl=find_packetctl(dev->out,dev->r_seq))
    {
        event_del(packetctl->retry_timerev);            
        del_packetctl(dev->out, packetctl);
    }

    return 0;
}

int rcst_lockreltxpath_nms2ncs_req(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    struct _STR_CHANNEL_ID_ *ptxchaId;
    struct _STR_CHANNEL_ID_ rxchaId;
    
    if(!ncs || !dev || !arg)
        return -1;
    
    ptxchaId=(struct _STR_CHANNEL_ID_ *)arg;
    if(dev_if_online(dev) && dev->state != RCST_ONLINE_OPENRX)
    {
        struct dev_obj *rx;
        if(-1 != ncs_getres_by_rcst(ptxchaId, &rxchaId, NULL))
            if(rx=ncs_find_rx(ncs, rxchaId.devId))
                ncs2rx_closerxpath_req(ncs,rx,&rxchaId);   
            
        ncs2rcst_lockreltxpath_req(ncs,dev,ptxchaId);
    }

    return 0;
}

int rcst_lockreltxpath_rcst2ncs_ack(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    char result;
    struct tlv_hdr *ptlv;
    struct packet_ctl *packetctl;
    
    if(!ncs || !dev || !arg)
        return -1;

    if(len != (TLV_HEAD_LEN+sizeof(result))){
        ncs_log(ERR,"%s the packet is error",__func__);
        return -1;
    }

    ptlv=(struct tlv_hdr *)arg;
    result=*(char *)(ptlv+1);
    if(result==FAILURE)
        ncs_log(WARN,"%s lock release failure",__func__);

    if(packetctl=find_packetctl(dev->out,dev->r_seq))
    {
        event_del(packetctl->retry_timerev);    
        del_packetctl(dev->out, packetctl);
    }
    
    struct _STR_CHANNEL_ID_ txchaId;
    txchaId.devId=dev->devId;
    txchaId.chaId=PATH_FIRST;
    ncs_relres_by_rcst(&txchaId);

    return 0;
}

int rcst_fsm_change(struct dev_obj *rcst,char event)
{
    int old_state;
    
    if(!rcst)
        return -1;
    
    if(event <= RCST_FSM_STATE_NULL
        || event >= RCST_FSM_STATE_MAX)
        return 0;

    old_state=rcst->state;
    rcst->state = RCST_FSM[rcst->state][event].n_state;
    
    if(0 != set_modemfsm_state(rcst))
         ncs_log(ERR,"%s update database rcst state failure",__func__);

    if(old_state != rcst->state)
        ncs2nms_report_devstate(rcst);

    return 0;
}

FSM_STATE RCST_FSM[RCST_FSM_STATE_MAX-1][RCST_FSM_EVENT_MAX-1]=
{
{  
    /* ----------------- offline state: 1-----------------------*/
    {rcst_logon_rcst2ncs_req,RCST_OFFLINE},           /*Receive_Rcst_Logon_Req*/
    {rcst_logon_success,RCST_ONLINE},      	/*Rcst_Auth_Success*/
    {NULL,RCST_OFFLINE},      			          /*Rcst_Auth_Failure*/
    {NULL,RCST_OFFLINE},                              /*Receive_Rcst_Res_Req*/
    {NULL,RCST_OFFLINE},                              /*Rcst_Resalloc_Success*/
    {NULL,RCST_OFFLINE},                              /*Rcst_Resalloc_Failure*/
    {NULL,RCST_OFFLINE},                              /*Receive_Rcst_Relres_Req*/
    {NULL,RCST_OFFLINE},                            /*Receive_Nms_Logoff_Req*/
    {NULL,RCST_OFFLINE},                            /*Receive_Rcst_Logoff_Req*/
    {NULL,RCST_OFFLINE},                             /*Receive_Nms_Relres_Req*/
    {NULL,RCST_OFFLINE},                             /*Receive_RxEms_CloseRcstTx_Req*/
    {NULL,RCST_OFFLINE},   				   /*Receive_Rcst_CloseTx_Ack*/
    {NULL,RCST_OFFLINE},                              /*Receive_RxEms_OpenRxpath_Success*/
    {NULL,RCST_OFFLINE},      				 /*RECEIVE_RCST_LOGOFF_ACK*/
    {NULL,RCST_OFFLINE},                           /*Poll_Rcst_Offline*/
    {rcst_locktxpath_nms2ncs_req,RCST_OFFLINE},         /*Receive_NMS_LOCKTXPATH_Req*/
    {rcst_locktxpath_rcst2ncs_ack,RCST_OFFLINE},        /*Receive_Rcst_Lock_Ack*/
    {rcst_lockreltxpath_nms2ncs_req,RCST_OFFLINE},    /*Receive_Nms_Lockrel_Req*/
    {rcst_lockreltxpath_rcst2ncs_ack,RCST_OFFLINE}, 		/*Receive_Rcst_Lockrel_Ack*/
    {NULL,RCST_OFFLINE},/*RECEIVE_RCST_FAULT*/
    {modem_updatepars,RCST_OFFLINE},    /*Receive_Nms_Parupdate_Req*/
    {NULL,RCST_OFFLINE},                          /*RECEIVE_RCST_BOD_REQ*/
    {NULL,RCST_ONLINE},                                /*RECEIVE_RCST_BODREL_REQ*/
},

{   
    /* ----------------- Online state : 2-----------------------*/
    {NULL,RCST_ONLINE},                                  /*Receive_Rcst_Logon_Req*/
    {NULL,RCST_ONLINE},      			            /*Rcst_Auth_Success*/
    {NULL,RCST_ONLINE},                                 /*Rcst_Auth_Failure*/
    {rcst_allocres_rcst2ncs_req,RCST_ONLINE},         /*Receive_Rcst_Res_Req*/
    {rcst_allocres_success,RCST_ONLINE_OPENRX},     /*Rcst_Resalloc_Success*/
    {rcst_allocres_failure,RCST_ONLINE},                   /*Rcst_Resalloc_Failure*/
    {NULL,RCST_ONLINE},                                  /*Receive_Rcst_Relres_Req*/
    {rcst_logoff_nms2ncs_req,RCST_OFFLINE},           /*Receive_Nms_Logoff_Req*/
    {rcst_logoff_rcst2ncs_req,RCST_OFFLINE},		/*Receive_Rcst_Logoff_Req*/
    {NULL,RCST_ONLINE},                                  /*Receive_Nms_Relres_Req*/
    {NULL,RCST_ONLINE},                                  /*Receive_RxEms_CloseRcstTx_Req*/
    {NULL,RCST_ONLINE},   			             /*Receive_Rcst_CloseTx_Ack*/
    {NULL,RCST_ONLINE},                                  /*Receive_RxEms_OpenRxpath_Success*/
    {NULL,RCST_ONLINE},      		                /*RECEIVE_RCST_LOGOFF_ACK*/
    {poll_rcst_offline,RCST_OFFLINE},            /*Poll_Rcst_Offline*/
    {rcst_locktxpath_nms2ncs_req,RCST_ONLINE},      /*Receive_Nms_Lock_Req*/
    {rcst_locktxpath_rcst2ncs_ack,RCST_ONLINE},  			            /*Receive_Rcst_Lock_Ack*/
    {rcst_lockreltxpath_nms2ncs_req,RCST_ONLINE_RELRES},    /*Receive_Nms_Lockrel_Req*/
    {rcst_lockreltxpath_rcst2ncs_ack,RCST_ONLINE}, 			                    /*Receive_Rcst_Lockrel_Ack*/ 
    {rcst_procfault_rcst2ncs,RCST_ONLINE},/*RECEIVE_RCST_FAULT*/
    {modem_updatepars,RCST_ONLINE},             /*Receive_Nms_Parupdate_Req*/ 
    {NULL,RCST_ONLINE},          			        /*RECEIVE_RCST_BOD_REQ*/
    {NULL,RCST_ONLINE},                                /*RECEIVE_RCST_BODREL_REQ*/
},

{   
    /* -------------- Online_openrx state : 3 -------------------*/
    {NULL,RCST_ONLINE_OPENRX},                          /*Receive_Rcst_Logon_Req*/
    {NULL,RCST_ONLINE},      		                     /*Rcst_Auth_Success*/
    {NULL,RCST_ONLINE_RELRES},           		    /*Rcst_Auth_Failure*/
    {NULL,RCST_ONLINE_OPENRX},   				/*Receive_Rcst_Res_Req*/
    {rcst_allocres_success,RCST_ONLINE_OPENRX},                       /*Rcst_Resalloc_Success*/
    {rcst_allocres_failure,RCST_ONLINE},                       /*Rcst_Resalloc_Failure*/
    {rcst_relres_rcst2ncs_req,RCST_ONLINE_RELRES},      /*Receive_Rcst_Relres_Req*/
    {rcst_logoff_nms2ncs_req,RCST_OFFLINE_RELRES},     /*Receive_Nms_Logoff_Req*/
    {rcst_logoff_rcst2ncs_req,RCST_OFFLINE},	    /*Receive_Rcst_Logoff_Req*/
    {rcst_relres_nms2ncs_req,RCST_ONLINE_RELRES},     /*Receive_Nms_Resrel_Req*/
    {rcst_closercst_rx2rcst_req,RCST_ONLINE},                   /*Receive_RxEms_CloseRcstTx_Req*/
    {NULL,RCST_ONLINE_OPENRX},   			 /*Receive_Rcst_CloseTx_Ack*/
    {rcst_openrx_success,RCST_ACTIVE},		  /*Receive_RxEms_OpenRxpath_Success*/
    {NULL,RCST_ONLINE_OPENRX},      				 /*RECEIVE_RCST_LOGOFF_ACK*/
    {poll_rcst_offline,RCST_OFFLINE},     /*Poll_Rcst_Offline*/
    {NULL,RCST_ONLINE_OPENRX},  	/*Receive_Nms_Lock_Req*/
    {NULL,RCST_ONLINE_OPENRX},  			    /*Receive_Rcst_Lock_Ack*/
    {NULL,RCST_ONLINE_OPENRX}, 			    /*Receive_Nms_Lockrel_Req*/
    {NULL,RCST_ONLINE_OPENRX}, 			    /*Receive_Rcst_Lockrel_Ack*/  
    {rcst_procfault_rcst2ncs,RCST_ONLINE},/*RECEIVE_RCST_FAULT*/
    {modem_updatepars,RCST_ONLINE_OPENRX},    /*Receive_Nms_Parupdate_Req*/ 
    {NULL,RCST_ONLINE_OPENRX},   			    /*RECEIVE_RCST_BOD_REQ*/
    {NULL,RCST_ONLINE},                                /*RECEIVE_RCST_BODREL_REQ*/
},

{   
    /* ------------------- active state : 4 --------------------*/
    {NULL,RCST_ACTIVE},                                      /*Receive_Rcst_Logon_Req*/
    {NULL,RCST_ACTIVE},      		 			/*Rcst_Auth_Success*/
    {NULL,RCST_ACTIVE},        			            /*Rcst_Auth_Failure*/
    {NULL,RCST_ACTIVE},             			        /*Receive_Rcst_Res_Req*/
    {NULL,RCST_ACTIVE},              			        /*Rcst_Resalloc_Success*/
    {NULL,RCST_ACTIVE},             			        /*Rcst_Resalloc_Failure*/
    {rcst_relres_rcst2ncs_req,RCST_ONLINE_RELRES},  	/*Receive_Rcst_Relres_Req*/
    {rcst_logoff_nms2ncs_req,RCST_OFFLINE_RELRES}, 	/*Receive_Nms_Logoff_Req*/
    {rcst_logoff_rcst2ncs_req,RCST_OFFLINE},	 /*Receive_Rcst_Logoff_Req*/
    {rcst_relres_nms2ncs_req,RCST_ONLINE_RELRES}, 		/*Receive_Nms_Relres_Req*/
    {rcst_closercst_rx2rcst_req,RCST_ONLINE_RELRES},    	/*Receive_RxEms_CloseRcstTx_Req*/
    {NULL,RCST_ACTIVE},   			            /*Receive_Rcst_CloseTx_Ack*/
    {NULL,RCST_ACTIVE}, 			    		        /*Receive_RxEms_OpenRxpath_Success*/
    {NULL,RCST_ACTIVE},             			    /*RECEIVE_RCST_LOGOFF_ACK*/
    {poll_rcst_offline,RCST_OFFLINE},	    /*Poll_Rcst_Offline*/
    {rcst_locktxpath_nms2ncs_req,RCST_ACTIVE},     /*Receive_Nms_Lock_Req*/
    {rcst_locktxpath_rcst2ncs_ack,RCST_ACTIVE},  	    /*Receive_Rcst_Lock_Ack*/
    {rcst_lockreltxpath_nms2ncs_req,RCST_ONLINE_RELRES}, /*Receive_Nms_Lockrel_Req*/
    {rcst_lockreltxpath_rcst2ncs_ack,RCST_OFFLINE}, 			                /*Receive_Rcst_Lockrel_Ack*/ 
    {rcst_procfault_rcst2ncs,RCST_ONLINE_RELRES},/*RECEIVE_RCST_FAULT*/
    {modem_updatepars,RCST_ACTIVE},  		    /*Receive_Nms_Parupdate_Req*/
    {rcst_bod_rcst2ncs_req,RCST_ONLINE_OPENRX},       /*RECEIVE_RCST_BOD_REQ*/
    {rcst_bodrel_rcst2ncs_req,RCST_ONLINE_OPENRX},   /*RECEIVE_RCST_BODREL_REQ*/
},

{   
    /* ------------------ online_relres state : 5 -----------------*/
    {NULL, RCST_ONLINE_RELRES},              	        /*Receive_Rcst_Logon_Req*/
    {NULL, RCST_ONLINE_RELRES},      		 	/*Rcst_Auth_Success*/
    {NULL, RCST_ONLINE_RELRES},             		/*Rcst_Auth_Failure*/
    {NULL, RCST_ONLINE_RELRES},             		/*Receive_Rcst_Res_Req*/
    {NULL, RCST_ONLINE_RELRES},              	        /*Rcst_Resalloc_Success*/
    {NULL, RCST_ONLINE_RELRES},             		/*Rcst_Resalloc_Failure*/
    {rcst_relres_rcst2ncs_req,RCST_ONLINE_RELRES},  	/*Receive_Rcst_Relres_Req*/
    {rcst_logoff_nms2ncs_req,RCST_OFFLINE_RELRES}, 	    /*Receive_Nms_Logoff_Req*/
    {rcst_logoff_rcst2ncs_req,RCST_OFFLINE}, 		/*Receive_Rcst_Logoff_Req*/
    {NULL,RCST_ONLINE_RELRES}, 		/*Receive_Nms_Relres_Req*/
    {NULL,RCST_ONLINE_RELRES},    	    /*Receive_RxEms_CloseRcstTx_Req*/
    {rcst_relres_rcst2ncs_ack,RCST_ONLINE},    /*Receive_Rcst_CloseTx_Ack*/
    {NULL,RCST_ONLINE_RELRES},            		         /*Receive_RxEms_OpenRxpath_Success*/
    {NULL,RCST_ONLINE_RELRES},                              /*RECEIVE_RCST_LOGOFF_ACK*/
    {poll_rcst_offline,RCST_ONLINE_RELRES},	   	/*Poll_Rcst_Offline*/
    {NULL,RCST_ONLINE_RELRES},  					/*Receive_Nms _Lock_Req*/
    {NULL,RCST_ONLINE_RELRES},  		                /*Receive_Rcst_Lock_Ack*/
    {NULL,RCST_ONLINE_RELRES}, 					/*Receive_Nms_Lockrel_Req*/
    {rcst_lockreltxpath_rcst2ncs_ack,RCST_ONLINE_RELRES}, 			        /*Receive_Rcst_Lockrel_Ack*/
    {rcst_procfault_rcst2ncs,RCST_ONLINE_RELRES},/*RECEIVE_RCST_FAULT*/
    {modem_updatepars,RCST_ONLINE_RELRES},  		   		/*Receive_Nms_Parupdate_Req*/
    {NULL,RCST_ONLINE},              /*RECEIVE_RCST_BOD_REQ*/
    {NULL,RCST_ONLINE},                                /*RECEIVE_RCST_BODREL_REQ*/
},

{   
    /* ------------------ RCST_OFFLINE_RELRES state: 6 --------------------*/
    {NULL,RCST_OFFLINE_RELRES},              	/*Receive_Rcst_Logon_Req*/
    {NULL,RCST_OFFLINE_RELRES},      		 	/*Rcst_Auth_Success*/
    {NULL,RCST_OFFLINE_RELRES},             		/*Rcst_Auth_Failure*/
    {NULL,RCST_OFFLINE_RELRES},             		/*Receive_Rcst_Res_Req*/
    {NULL,RCST_OFFLINE_RELRES},              	/*Rcst_Resalloc_Success*/
    {NULL,RCST_OFFLINE_RELRES},             		/*Rcst_Resalloc_Failure*/
    {NULL,RCST_OFFLINE_RELRES},  				/*Receive_Rcst_Relres_Req*/
    {rcst_logoff_nms2ncs_req,RCST_OFFLINE_RELRES}, 		/*Receive_Nms_Logoff_Req*/
    {rcst_logoff_rcst2ncs_req,RCST_OFFLINE}, 		/*Receive_Rcst_Logoff_Req*/
    {NULL,RCST_OFFLINE_RELRES}, 					/*Receive_Nms_Relres_Req*/
    {NULL,RCST_OFFLINE_RELRES},    				/*Receive_RxEms_CloseRcstTx_Req*/
    {rcst_relres_rcst2ncs_ack,RCST_OFFLINE},   /*Receive_Rcst_CloseTx_Ack*/
    {NULL,RCST_OFFLINE_RELRES},            		/*Receive_RxEms_OpenRxpath_Success*/
    {rcst_logoff_rcst2ncs_ack,RCST_OFFLINE},   /*RECEIVE_RCST_LOGOFF_ACK*/
    {NULL,RCST_OFFLINE_RELRES},	                    /*Poll_Rcst_Offline*/
    {NULL,RCST_OFFLINE_RELRES},  			      /*Receive_Nms _Lock_Req*/
    {NULL,RCST_OFFLINE_RELRES},  			      /*Receive_Rcst_Lock_Ack*/
    {NULL,RCST_OFFLINE_RELRES}, 				   /*Receive_Nms_Lockrel_Req*/
    {rcst_lockreltxpath_rcst2ncs_ack,RCST_OFFLINE}, 			    /*Receive_Rcst_Lockrel_Ack*/
    {rcst_procfault_rcst2ncs,RCST_OFFLINE_RELRES},/*RECEIVE_RCST_FAULT*/
    {NULL,RCST_OFFLINE_RELRES},  		   	   /*Receive_Nms_Parupdate_Req*/
    {NULL,RCST_OFFLINE},             /*RECEIVE_RCST_BOD_REQ*/
    {NULL,RCST_ONLINE},                                /*RECEIVE_RCST_BODREL_REQ*/
}
};


int ncs_closetx_by_rxcha(struct ncs_object *ncs,
    struct _STR_CHANNEL_ID_ *prxcha)
{
    int ret,event;
    FSM_CALLFUNC func;
    struct dev_obj *rcst;
    struct _STR_CHANNEL_ID_ txcha;
    
    if(ncs_getrcst_by_rx(prxcha,&txcha))
    {
        if(rcst=ncs_find_rcst(ncs,txcha.devId))
        {
            event=RECEIVE_RXEMS_CLOSERCSTTX_REQ;
            if(func=RCST_FSM[rcst->state][event].func)
                ret=func(ncs,rcst,&txcha,sizeof(struct _STR_CHANNEL_ID_));
            if(-1 != ret)
                rcst_fsm_change(rcst, event);
        }
    }

    return 0;
}

int rx_delrx_nms2ncs(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    if(!ncs && !dev)
        return -1;
    
        ncs_del_modem(ncs,dev);
    return 0;
}

int rx_poll_offline(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    struct _STR_CHANNEL_ID_ rxchaId;
    
    if(!ncs || !dev)
        return -1;
    
    rxchaId.devId=dev->devId;
    for(int i=PATH_FIRST;i<=PATH_FOURTH;i++)
    {
        rxchaId.chaId=i;
        ncs_closetx_by_rxcha(ncs, &rxchaId);
    }
    
    return 0;
}

int rx_logon_success(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    struct dev_set *rxset;

    if(!ncs || !dev)
        return -1;

    rxset=ncs->sig_set;
    rxset->count += 1;
        
    /*start poll timer event*/
    if(!rxset->poll_timerev)       
        ncs_start_dev_poll_event(ncs,dev);
     
    /*send pp's configure to sigems*/
    ncs2rx_send_allcfg(ncs,dev);

    return 0;
}

int rx_closerxpath_req(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    return 0;
}

int rx_relres_nms2ncs_req(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    int event;
    FSM_CALLFUNC func;
    struct _STR_CHANNEL_ID_ *prxcha;
    
    if(!ncs || !dev || !arg)
        return -1;

    prxcha=(struct _STR_CHANNEL_ID_ *)arg;
    if(dev->devId != prxcha->devId)
        return -1;

    ncs2rx_closerxpath_req(ncs, dev,prxcha);
    
    if(prxcha->chaId==0XFF)
    {
        struct _STR_CHANNEL_ID_ rxcha;
        rxcha.devId=prxcha->devId;
        for(int i=PATH_FIRST;i<=PATH_FOURTH;i++)
        {
            rxcha.chaId=i;
            ncs_closetx_by_rxcha(ncs,&rxcha);
        }
    }
    else
        ncs_closetx_by_rxcha(ncs,prxcha);

    return 0;
}

int rx_logon_rx2ncs_req(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    char result;
    FSM_CALLFUNC func;
    
    if(!ncs || !dev || !arg || !len)
        return -1;

    if(dev->state == ONLINE && dev->try_flag == TRUE)
        ncs2rx_logon_ack(ncs,dev,SUCCESS);
    else if(dev->state == OFFLINE)
    {
        result=logon_modem2ncs_req(ncs,dev,(struct tlv_hdr *)arg,len);
        ncs2rx_logon_ack(ncs,dev,result);

        if(result == SUCCESS)
        {
            if(func=RX_FSM[dev->state][RXEMS_AUTH_SUCCESS].func)
                func(ncs,dev,NULL,0);
            sig_fsm_change(dev, RXEMS_AUTH_SUCCESS); 
        }    
    }
        
    return -1;   
}

int rx_openrxpath_rx2ncs_ack(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    int i=len;
    int event,rxchanum;
    struct tlv_hdr *ptlv;
    struct dev_obj *rcst,*rx=NULL;
    struct _STR_RESULT_ *presult;
    struct _STR_CHANNEL_ID_ *prxchaId;
    struct _STR_CHANNEL_ID_ txchaId;
    struct _STR_CHANNEL_ID_ newrxchaId;
    FSM_CALLFUNC func;

    ptlv=(struct tlv_hdr *)arg;
    if(len < (htons(ptlv->len)+TLV_HEAD_LEN))
        return -1;

    char type;
    short msglen;
    while(i <= 0)
    {
        type=ptlv->type;
        msglen=htons(ptlv->len);
        
        if(i < (msglen+TLV_HEAD_LEN))
            return -1;

        if(ptlv->type == _RESULT_)
            presult=(struct _STR_RESULT_ *)(ptlv+1);
        else if(ptlv->type == _CHANNEL_ID_)
            prxchaId=(struct _STR_CHANNEL_ID_ *)(ptlv+1);

        i -= (msglen+TLV_HEAD_LEN);
        ptlv=(struct tlv_hdr *)((char *)(ptlv+1)+msglen);    
    }

    if(ncs_getrcst_by_rx(prxchaId,&txchaId)
        && (rcst=ncs_find_rcst(ncs,txchaId.devId)))
    {      
        presult=(struct _STR_RESULT_ *)(ptlv+1);
        if(SUCCESS == presult->result)
            event=RECEIVE_RXEMS_OPENRXPATH_SUCCESS;
        else
        {
            /*realloc rxpath resource for rcst*/         
            if(ncs_reallocres_by_rcst(&txchaId,&newrxchaId,NULL))
            {
                rxchanum=newrxchaId.chaId;
                event=RCST_RESALLOC_SUCCESS;
                rx=ncs_find_rx(ncs,newrxchaId.devId);
            }
            else
                event=RCST_RESALLOC_FAILURE;
        }
  
        if(func=RCST_FSM[rcst->state][event].func)
            if(-1 !=func(ncs,rcst,rx,rxchanum))
                rcst_fsm_change(rcst,event);
    }
    
    return -1;
}

int rx_closerxpath_rx2ncs_ack(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    char result;
    struct tlv_hdr *ptlv;
    struct packet_ctl *packetctl;
    
    if(!ncs || !dev || !arg)
        return -1;

    if(len != (TLV_HEAD_LEN+sizeof(result))){
        ncs_log(ERR,"%s the packet is error",__func__);
        return -1;
    }

    ptlv=(struct tlv_hdr *)arg;
    result=*(char *)(ptlv+1);
    if(result==FAILURE)
        ncs_log(WARN,"%s close rxpath failure",__func__);

    if((packetctl=find_packetctl(dev->out,dev->r_seq))){
        if(event_del(packetctl->retry_timerev))
            ncs_log(ERR,"%s delete timer event failure",__func__);         
        del_packetctl(dev->out, packetctl);
    }
        
    return 0;
}


int rx_lockrxpath_nms2ncs_req(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    struct carrierLock_msg *pcarrierlock;

    if(!ncs || !dev || !arg)
        return -1;
    
    pcarrierlock=(struct carrierLock_msg *)arg;
    if((dev->devId != pcarrierlock->rxdevId)
        || (pcarrierlock->rxchaId < PATH_FIRST)
        || (pcarrierlock->rxchaId > PATH_FOURTH))
       return -1;
    
    return 0;
}

int rx_fsm_change(struct dev_obj *rx,char event)
{
    int old_state;
    
    if(!rx)
        return -1;
    
    if(event <= RXEMS_FSM_EVENT_NULL
        || event >= RXEMS_FSM_EVENT_MAX)
        return 0;

    old_state=rx->state;
    rx->state = RX_FSM[rx->state][event].n_state;
    
    if(0 != set_modemfsm_state(rx))
         ncs_log(ERR,"%s update database rx state failure",__func__);

    if(old_state != rx->state)
        ncs2nms_report_devstate(rx);

    return 0;
}

FSM_STATE RX_FSM[FSM_STATE_MAX-1][RXEMS_FSM_EVENT_MAX-1]={
/*------------------------offline: 1 ------------------------*/
{
    {rx_logon_rx2ncs_req,OFFLINE},    	/*Receive_RxEms_Logon_Req*/
    {rx_logon_success,ONLINE},		/*RxEms_Auth_Success*/
    {NULL,OFFLINE},			      	/*RxEms_Auth_Failure*/
    {NULL,OFFLINE},			      	/*Poll_RxEms_Offline*/
    {NULL,OFFLINE},			      	/*Receive_Rcst_OpenRxpath_Req*/
    {NULL,OFFLINE},				/*Receive_RxEms_OpenRxpath_ACK*/
    {NULL,OFFLINE},			      	/*Receive_Rcst_CloseRxpath_Req*/
    {NULL,OFFLINE},  				/*Receive_RxEms_CloseRxpath_ACK*/
    {modem_updatepars,OFFLINE},    /*Receive_NMS_ParupdateRx_Req*/
    {NULL,OFFLINE},  			  	/*Receive_Nms_RelresRx_Req*/
    {rx_lockrxpath_nms2ncs_req,OFFLINE},      /*Receive_NMS_LockRxpath_Req*/
    {NULL,OFFLINE},    				/*Receive_RxEms_LockRxpath_Ack*/
    {NULL,OFFLINE}, 	/*Receive_NMS_LockrelRxpath_Req*/
    {NULL,OFFLINE},    				/*Receive_RxEms_LockrelRxpath_Ack*/
},
/*-----------------------Online: 1 ------------------*/
{
    {rx_logon_rx2ncs_req,ONLINE},    		/*Receive_RxEms_Logon_Req*/
    {NULL,ONLINE},			      		    /*RxEms_Auth_Success*/
    {NULL,OFFLINE},			      		    /*RxEms_Auth_Failure*/
    {rx_poll_offline,OFFLINE},			      		/*Poll_RxEms_Offline*/
    {NULL,ONLINE}, 			/*Receive_Rcst_OpenRxpath_Req*/
    {rx_openrxpath_rx2ncs_ack,ONLINE},		/*Receive_RxEms_OpenRxpath_ACK*/
    {NULL,ONLINE},			/*Receive_Rcst_CloseRxpath_Req*/
    {rx_closerxpath_rx2ncs_ack,ONLINE},  	/*Receive_RxEms_CloseRxpath_ACK*/
    {modem_updatepars,ONLINE},    		/*Receive_NMS_ParupdateRx_Req*/
    {rx_relres_nms2ncs_req, ONLINE},  	  		/*Receive_Nms_RelresRx_Req*/
    {rx_lockrxpath_nms2ncs_req,ONLINE},   		/*Receive_NMS_LockRxpath_Req*/
    {NULL,ONLINE},    	                            /*Receive_RxEms_LockRxpath_Ack*/
    {NULL,ONLINE}, 		/*Receive_NMS_LockrelRxpath_Req*/
    {NULL,ONLINE},                                 /*Receive_RxEms_LockrelRxpath_Ack*/
}
};

/*SIGEMS's FSM STATE change and process*/
int logon_sig2ncs_req(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{   
    char result;
    FSM_CALLFUNC func;

    if(!ncs || !dev || !arg || !len)
        return -1;

    if(dev->state == ONLINE && dev->try_flag == TRUE)
        ncs2sig_logon_ack(ncs,dev,SUCCESS);
    else if(dev->state == OFFLINE)
    {
        result=logon_modem2ncs_req(ncs,dev,(struct tlv_hdr *)arg,len);
        ncs2sig_logon_ack(ncs,dev,result);

        if(result == SUCCESS)
        {
            if(func=SIG_FSM[dev->state][SIGEMS_AUTH_SUCCESS].func)
                func(ncs,dev,NULL,0);
            sig_fsm_change(dev, SIGEMS_AUTH_SUCCESS); 
        }    
    }
        
    return 0;   
}

int sig_logon_success(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    struct dev_set *sigset;
    struct timeval timeout;

    if(!ncs || !dev)
        return -1;

    sigset=ncs->sig_set;
    sigset->count += 1;

    if(!ncs_get_active_sig(ncs))
        SET_BIT(dev->flag,DEV_FLAG_ACTIVE);
    else
        UNSET_BIT(dev->flag,DEV_FLAG_ACTIVE);
        
    /*start poll timer event*/
    if(!sigset->poll_timerev)
        ncs_start_dev_poll_event(ncs,dev);
    
    if(!ncs->send_ib_timerev)
        ncs_start_send_Ib_event(ncs,dev);
        
    /*send pp's configure to sigems*/
    ncs2sig_send_allcfg(ncs,dev);

    return 0;
}

int sig_poll_offline(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    struct dev_set *sigset;
    
    if(!ncs || !dev)
        return -1;

    if(CHECK_BIT(dev->flag,DEV_FLAG_ACTIVE))
        UNSET_BIT(dev->flag,DEV_FLAG_ACTIVE);
    
    sigset=ncs->sig_set;
    sigset->count --;
    if(!sigset->count){
        event_del(sigset->poll_timerev);
        sigset->poll_timerev=NULL;
        return 0;
    }
    
    /*To do: get new sigems and open*/
    //if(ncs_sigDevSwitch_breakdown())
}

int sig_fsm_change(struct dev_obj *sig,char event)
{
    int old_state;
    
    if(!sig)
        return -1;
    
    if(event <= SIGEMS_FSM_EVENT_NULL
        || event >= RSIGEMS_FSM_EVENT_MAX)
        return 0;

    old_state=sig->state;
    sig->state = SIG_FSM[sig->state][event].n_state;
    
    if(0 != set_modemfsm_state(sig))
         ncs_log(ERR,"%s update database sig state failure",__func__);

    if(old_state != sig->state)
        ncs2nms_report_devstate(sig);
    
    return 0;
}

FSM_STATE SIG_FSM[FSM_STATE_MAX-1][RSIGEMS_FSM_EVENT_MAX-1]=
{
/*offline,online*/
/*----------------------------offline------------------------*/
{
    {logon_sig2ncs_req,OFFLINE},                /*Receive_SigEms_Logon_Req*/
    {sig_logon_success,ONLINE},		    /*SigEms_Auth_Success*/
    {NULL,OFFLINE},			      		    /*SigEms_Auth_Failure*/
    {NULL,OFFLINE},			      		    /*Poll_SigEms_Offline*/
    {modem_updatepars,OFFLINE},              /*Receive_Nms_ParupdateSig_Req*/
},
/*--------------------------online------------------------*/
{
    {logon_sig2ncs_req, ONLINE},                /*Receive_SigEms_Logon_Req*/
    {NULL,ONLINE},			      		    /*SigEms_Auth_Success*/
    {NULL,OFFLINE},			      		    /*SigEms_Auth_Failure*/
    {sig_poll_offline,OFFLINE},		          /*Poll_SigEms_Offline*/
    {modem_updatepars,ONLINE},    	    /*Receive_Nms_ParupdateSig_Req*/
}
};

int pp_fsm_change(struct dev_obj *pp,char event)
{
    int old_state;
    
     if(!pp)
        return -1;
    
    if(event <= PP_FSM_EVENT_NULL 
        || event >= PP_FSM_EVENT_MAX)
        return -1;

    old_state=pp->state ;
    pp->state = PP_FSM[pp->state][event].n_state;

    /*set pp state in database*/
    set_ppfsm_state(pp);

    if(old_state != pp->state)
        ncs2nms_report_devstate(pp);
 
    return 0;
}

/*PP's FSM STATE change and process*/
int pp_poll_offline(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    struct dev_set *ppset;
    struct dev_obj *pp=dev;
    
    if(!ncs || !dev)
        return -1;

    ppset = ncs->pp_set;
    ppset->count = 0;
    
    /*cancel the poll timer event*/
    event_del(ppset->poll_timerev);
    ppset->poll_timerev=NULL;
    
    return 0;        
}

int pp_logon_success(struct ncs_object *ncs,
    struct dev_obj *dev,void *arg,int len)
{
    struct dev_set *ppset;
    
    if(!dev || !ncs)
        return -1;

    ppset = ncs->pp_set;
    ppset->count += 1;    /*the count of online state to + 1*/

    if(ppset->count)
        ncs_start_dev_poll_event(ncs,dev);

    /*send pp's configure to pp dev*/
    ncs2pp_send_allcfg(ncs,dev);

    return 0;    
}

FSM_STATE PP_FSM[FSM_STATE_MAX-1][PP_FSM_EVENT_MAX-1]=
{
/*-------------offline--------------*/
{
    {logon_pp2ncs_req,OFFLINE},         /*Receive_PP_Logon_Req*/
    {pp_logon_success,ONLINE},	           /*PP_Auth_Success*/
    {NULL,OFFLINE},			      	    /*PP_Auth_Failure*/
    {NULL,OFFLINE},			      	    /*Poll_PP_Offline*/
    {pp_updatepars,OFFLINE},         /*Receive_Nms_ParupdatePP_Req*/
},
/*-------------online--------------*/
{
    {logon_pp2ncs_req,ONLINE},           /*Receive_PP_Logon_Req*/
    {NULL,ONLINE},			      	    /*PP_Auth_Success*/
    {NULL,OFFLINE},			      	    /*PP_Auth_Failure*/
    {pp_poll_offline,OFFLINE},		    /*Poll_pp_Offline*/
    {pp_updatepars,ONLINE},    	    /*Receive_Nms_ParupdatePP_Req*/
}
};


